package com.decent.manager.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.decent.common.bo.MessageBean;
import com.decent.common.bo.SimpleMessage;
import com.decent.common.entity.manager.SystemMenu;
import com.decent.common.enums.CommonStatusEnum;
import com.decent.common.enums.ErrorCodeEnum;
import com.decent.common.enums.manager.MenuTypeEnum;
import com.decent.common.exception.ErrorCodeException;
import com.decent.manager.config.security.context.LoginContext;
import com.decent.manager.constant.ManagerConstants;
import com.decent.manager.system.auth.vo.LoginMenuTreeNode;
import com.decent.manager.system.dao.SystemMenuDao;
import com.decent.manager.system.dto.SystemMenuDTO;
import com.decent.manager.system.service.SystemMenuService;
import com.decent.manager.system.vo.SystemMenuVO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 系统菜单管理
 *
 * @author wangyan
 **/
@Service
public class SystemMenuServiceImpl implements SystemMenuService {
    @Resource
    private LoginContext loginContext;
    @Resource
    private SystemMenuDao systemMenuDao;

    @Override
    public MessageBean add(SystemMenuDTO sysMenuParam) {
        // 校验参数
        checkParam(sysMenuParam, false);
        SystemMenu sysMenu = new SystemMenu();
        BeanUtil.copyProperties(sysMenuParam, sysMenu);
        // 设置新的pid
        String newPids = createNewPids(sysMenuParam.getPid());
        sysMenu.setPids(newPids);
        sysMenu.setCreator(loginContext.getLoginUser().getUserName());
        sysMenu.setMenuStatus(CommonStatusEnum.NORMAL);
        sysMenu.setVisibility(MenuTypeEnum.INNER_MENU != sysMenu.getMenuType());
        systemMenuDao.addSystemMenu(sysMenu);
        return new MessageBean(ErrorCodeEnum.OK);
    }

    /**
     * 创建pids的值
     * <p>
     * 如果pid是0顶级节点，pids就是 [0],
     * <p>
     * 如果pid不是顶级节点，pids就是 pid菜单的pids + [pid] + ,
     */
    private String createNewPids(Long pid) {
        if (pid.equals(0L)) {
            return ManagerConstants.LEFT_SQUARE_BRACKETS + 0 + ManagerConstants.RIGHT_SQUARE_BRACKETS
                    + ManagerConstants.COMMA;
        } else {
            //获取父菜单
            SystemMenu parentMenu = systemMenuDao.getById(pid);
            return parentMenu.getPids()
                    + ManagerConstants.LEFT_SQUARE_BRACKETS + pid + ManagerConstants.RIGHT_SQUARE_BRACKETS
                    + ManagerConstants.COMMA;
        }
    }

    /**
     * 校验参数
     */
    private void checkParam(SystemMenuDTO sysMenuParam, boolean isExcludeSelf) {
        Long id = sysMenuParam.getId();
        String name = sysMenuParam.getMenuName();
        String code = sysMenuParam.getMenuCode();
        Long nameExist = systemMenuDao.nameExist(name);
        Long codeExist = systemMenuDao.codeExist(code);
        // 如果是编辑菜单时候，pid和id不能一致，一致会导致无限递归
        if (isExcludeSelf) {
            if (sysMenuParam.getId().equals(sysMenuParam.getPid())) {
                throw new ErrorCodeException(ErrorCodeEnum.NO, "父级菜单不能为当前节点");
            }
            // 如果是编辑，父id不能为自己的子节点
            List<Long> childIdListById = systemMenuDao.getChildIdListById(sysMenuParam.getId());
            if (ObjectUtil.isNotEmpty(childIdListById)) {
                if (childIdListById.contains(sysMenuParam.getPid())) {
                    throw new ErrorCodeException(ErrorCodeEnum.NO, "父节点不能为本节点的子节点");
                }
            }
            if (Objects.nonNull(nameExist) && !Objects.equals(nameExist, id)) {
                throw new ErrorCodeException(ErrorCodeEnum.NO, "菜单名称重复");
            }
            if (Objects.nonNull(codeExist) && !Objects.equals(codeExist, id)) {
                throw new ErrorCodeException(ErrorCodeEnum.NO, "菜单编码重复");
            }
            return;
        }
        if (Objects.nonNull(nameExist) || Objects.nonNull(codeExist)) {
            throw new ErrorCodeException(ErrorCodeEnum.NO, "菜单名称或编码重复");
        }
    }

    @Override
    public SimpleMessage delete(Long menuId) {
        //级联删除子节点
        systemMenuDao.deleteMenu(menuId);
        //级联删除该菜单及子菜单对应的角色-菜单表信息
        ArrayList<Long> ids = new ArrayList<>(systemMenuDao.getChildIdListById(menuId));
        ids.add(menuId);
        systemMenuDao.deleteRoleMenuListByMenuId(ids);
        return new SimpleMessage(ErrorCodeEnum.OK);
    }

    @Override
    public MessageBean edit(SystemMenuDTO sysMenuParam) {
        // 校验参数
        checkParam(sysMenuParam, true);
        // 获取修改的菜单的旧数据（库中的）
        SystemMenu oldMenu = this.querySysMenu(sysMenuParam.getId());
        // 本菜单旧的pids
        Long oldPid = oldMenu.getPid();
        String oldPids = oldMenu.getPids();
        // 生成新的pid和pids
        Long newPid = sysMenuParam.getPid();
        String newPids = this.createNewPids(sysMenuParam.getPid());
        // 是否更新子节点的pids的标识
        boolean updateSubPidsFlag = !newPid.equals(oldPid);
        // 开始更新所有子节点的配置
        if (updateSubPidsFlag) {
            // 查找所有叶子节点，包含子节点的子节点
            SystemMenuDTO queryParams = new SystemMenuDTO();
            queryParams.setId(oldMenu.getId());
            List<SystemMenuVO> list = systemMenuDao.list(queryParams);
            // 更新所有子节点的应用为当前菜单的应用
            if (ObjectUtil.isNotEmpty(list)) {
                // 更新所有子节点的pids
                list.forEach(child -> {
                    // 子节点pids组成 = 当前菜单新pids + 当前菜单id + 子节点自己的pids后缀
                    String oldParentCodesPrefix = oldPids + ManagerConstants.LEFT_SQUARE_BRACKETS + oldMenu.getId()
                            + ManagerConstants.RIGHT_SQUARE_BRACKETS + ManagerConstants.COMMA;
                    String oldParentCodesSuffix = child.getPids().substring(oldParentCodesPrefix.length());
                    String menuParentCodes = newPids + ManagerConstants.LEFT_SQUARE_BRACKETS + oldMenu.getId()
                            + ManagerConstants.RIGHT_SQUARE_BRACKETS + ManagerConstants.COMMA + oldParentCodesSuffix;
                    child.setPids(menuParentCodes);
                    child.setVisibility(MenuTypeEnum.INNER_MENU != child.getMenuType());
                    systemMenuDao.updateMenu(child);
                });
            }
        }
        // 拷贝参数到实体中
        BeanUtil.copyProperties(sysMenuParam, oldMenu);
        // 设置新的pids
        oldMenu.setPids(newPids);
        //不能修改状态，用修改状态接口修改状态
        oldMenu.setMenuStatus(null);
        oldMenu.setVisibility(MenuTypeEnum.INNER_MENU != oldMenu.getMenuType());
        systemMenuDao.updateMenu(oldMenu);
        return new MessageBean(ErrorCodeEnum.OK);
    }

    /**
     * 获取系统菜单
     */
    private SystemMenu querySysMenu(Long menuId) {
        SystemMenu sysMenu = systemMenuDao.getById(menuId);
        if (ObjectUtil.isNull(sysMenu)) {
            throw new ErrorCodeException(ErrorCodeEnum.NO, "菜单不存在");
        }
        return sysMenu;
    }

    /**
     * 转换ant页面使用的菜单
     *
     * @param roleMenus 角色菜单
     * @return list
     */
    @Override
    public List<LoginMenuTreeNode> convertSystemMenuToLoginMenu(List<SystemMenu> roleMenus) {
        return roleMenus.stream().map(sysMenu -> {
            LoginMenuTreeNode loginMenuTreeNode = new LoginMenuTreeNode();
            loginMenuTreeNode.setComponent(sysMenu.getComponent());
            loginMenuTreeNode.setId(sysMenu.getId());
            loginMenuTreeNode.setName(sysMenu.getMenuCode());
            loginMenuTreeNode.setPath(sysMenu.getRouter());
            loginMenuTreeNode.setPid(sysMenu.getPid());
            LoginMenuTreeNode.Meta mateItem = new LoginMenuTreeNode.Meta();
            mateItem.setIcon(sysMenu.getIcon());
            mateItem.setTitle(sysMenu.getMenuName());
            //设置的首页，默认打开此链接
            loginMenuTreeNode.setRedirect(sysMenu.getRedirect());
            //是否可见
            mateItem.setShow(sysMenu.getVisibility());
            loginMenuTreeNode.setMeta(mateItem);
            return loginMenuTreeNode;
        }).collect(Collectors.toList());
    }
}
